home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * "Irit" - the 3d (not only polygonal) solid modeller. *
- * *
- * Written by: Gershon Elber Ver 0.2, Mar. 1990 *
- ******************************************************************************
- * Module to convert infix expression given as ascii stream sequence into *
- * a binary tree, and evaluate it. *
- * All the objects are handled the same but the numerical one, which is *
- * moved as a RealType and not as an object (only internally within this *
- * module) as it is frequently used and consumes much less memory this way. *
- *****************************************************************************/
-
- #include <stdio.h>
- #include <ctype.h>
- #include <math.h>
- #include <string.h>
- #include "program.h"
- #include "allocate.h"
- #include "ctrl-brk.h"
- #include "inptprsg.h"
- #include "inptprsl.h"
- #include "objects.h"
- #include "overload.h"
- #include "windows.h"
-
- char IPGlblCharData[INPUT_LINE_LEN]; /* Used for both parse & eval. */
-
- static int IPGlblILastToken; /* Globals used by parser. */
- static InptPrsrEvalErrType
- IPGlblParseError = IPE_NO_ERR;
- static UserDefinedFuncDefType
- *IPGlblUserFunc = NULL;
- static FileStackStruct FileStack[FILE_STACK_SIZE]; /* Include file stack. */
- static int
- GlblEchoSource = TRUE,
- FileStackPtr = 0;
- static char
- UnGetChar = 0;
-
- /* Operator preceeding parser stack, and stack pointer: */
- static ParseTree *Stack[MAX_PARSER_STACK];
- static int
- ParserStackPointer = 0;
-
- #ifdef DEBUG1
- int MaxStackPointer = 0; /* Measure maximum depth of stack. */
- #endif /* DEBUG1 */
-
- static ParseTree *GenInputParseTree(void);
- static ParseTree *OperatorPrecedence(void);
- static int TestPreceeding(int Token1, int Token2);
- static char *UpdateCharErrorAux(int Token, ParseTree *Node);
- static int GetToken(RealType *Data);
- static int GetVarFuncToken(char *Token, RealType *Data);
- static void InptPrsrUnGetC(char c);
- static char InptPrsrGetC(int InString);
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Main module routine - generate parse tree and then tries to evaluate it. M
- * Returns TRUE if succesfull, otherwise check IPGlblParseError/EvalError. M
- * *
- * PARAMETERS: M
- * None M
- * *
- * RETURN VALUE: M
- * int: TRUE if successful, FALSE otherwise. M
- * *
- * KEYWORDS: M
- * InputParser M
- *****************************************************************************/
- int InputParser(void)
- {
- ParseTree *PTree;
-
- if (GlblFatalError) {
- GlblFatalError = FALSE;
- FlushToEndOfExpr(FALSE); /* Close all include files if any. */
- return TRUE;
- }
-
- PTree = GenInputParseTree(); /* Generate parse tree. */
-
- if (IPGlblParseError == IPE_NO_ERR) {
- # ifdef DEBUG1
- fprintf(stderr, "\nInput generated Parse tree (Max stack = %d)\n",
- MaxStackPointer);
- InptPrsrPrintTree(PTree, NULL);
- fprintf(stderr, "\n");
- # endif /* DEBUG1 */
- if (InptPrsrTypeCheck(PTree, 0) == ERROR_EXPR) { /* Type checking. */
- InptPrsrFreeTree(PTree); /* Not needed any more. */
- FlushToEndOfExpr(TRUE);/* Close all include files, & flush stdin.*/
- return FALSE;
- }
-
- InptPrsrEvalTree(PTree, 0); /* Evaluate it. */
- if (IPGlblEvalError != IPE_NO_ERR) {
- FlushToEndOfExpr(TRUE); /* Close include files, and flush stdin. */
- return FALSE;
- }
- }
- else {
- FlushToEndOfExpr(TRUE); /* Close all include files, and flush stdin. */
- return FALSE;
- }
-
- InptPrsrFreeTree(PTree); /* Not needed any more. */
-
- return !(IPGlblParseError || IPGlblEvalError);
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to convert the expression from stream f into a binary tree. *
- * Algorithm: Using operator precedence with the following grammer: *
- * EXPR ::= EXPR | EXPR + EXPR | EXPR - EXPR *
- * EXPR ::= EXPR | EXPR * EXPR | EXPR / EXPR *
- * EXPR ::= EXPR | EXPR ^ EXPR *
- * EXPR ::= EXPR | EXPR , EXPR | EXPR = EXPR *
- * EXPR ::= NUMBER | -EXPR | (EXPR) | FUNCTION *
- * FUCTION ::= FUNC(EXPR , EXPR , ...) *
- * Where FUNC might be function like arithmetics (SIN, COS etc.). *
- * Note that FUNC might have more than one operand, seperated by ','. *
- * *
- * Note the stream is terminated by semicolon character ';'. *
- * *
- * Left associativity for +, -, *, /, ^. *
- * Precedence of operators is as usual: *
- * <Highest> {unar minus} {^} {*, /} {+, -} <Lowest> *
- * *
- * Returns NULL if an error was found, and error is in IPGlblParseError *
- * *
- * PARAMETERS: *
- * None *
- * *
- * RETURN VALUE: *
- * ParseTree *: Constructed parsed tree. *
- *****************************************************************************/
- static ParseTree *GenInputParseTree(void)
- {
- ParseTree *Root;
- int i;
-
- IPGlblILastToken = 0; /* Used to hold last token read from stream. */
- IPGlblParseError = IPE_NO_ERR; /* No errors so far ... */
-
- Root = OperatorPrecedence();
-
- if (IPGlblParseError) {
- /* Free partialy allocated tree. */
- for (i = 0; i <= ParserStackPointer; i++)
- InptPrsrFreeTree(Stack[i]);
- return NULL; /* Error ! */
- }
- else
- return Root;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to allocate new ParseTree expression node. M
- * *
- * PARAMETERS: M
- * None M
- * *
- * RETURN VALUE: M
- * ParseTree *: Allocate a ParseTree node. M
- * *
- * KEYWORDS: M
- * ExprMalloc M
- *****************************************************************************/
- ParseTree *ExprMalloc(void)
- {
- ParseTree *p;
-
- p = (ParseTree *) IritMalloc(sizeof(ParseTree));
- p -> Right = p -> Left = NULL;
- p -> NodeKind = IP_OBJ_UNDEF;
- p -> PObj = NULL;
- p -> UserFunc = NULL;
- return p;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to free one expression node. M
- * *
- * PARAMETERS: M
- * Ptr: ParseTree to free. M
- * *
- * RETURN VALUE: M
- * void M
- * *
- * KEYWORDS: M
- * ExprFree M
- *****************************************************************************/
- void ExprFree(ParseTree *Ptr)
- {
- IritFree((VoidPtr) Ptr);
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to actually parse using operator precedence. *
- * Few Notes: *
- * 1. Parse the input with the help of GetToken routine. Input is redirected *
- * using the FileStack. *
- * 2. All tokens must be in the range of 0..999 as we use the numbers above *
- * it (adding 1000) to deactivate them in the handle searching (i.e. when *
- * they were reduced to sub.-expression). *
- * 3. Returns NULL pointer in case of an error. *
- * 4. See "Compilers - principles, techniques and tools" by Aho, Sethi & *
- * Ullman, pages 207-210. *
- * *
- * PARAMETERS: *
- * None *
- * *
- * RETURN VALUE: *
- * ParseTree *: Returned parsed tree. *
- *****************************************************************************/
- static ParseTree *OperatorPrecedence(void)
- {
- int Token, LowHandle, Temp1, Temp2;
- RealType Data;
-
- # ifdef DEBUG1
- MaxStackPointer = 0;
- # endif /* DEBUG1 */
-
- ParserStackPointer = 0;
-
- /* Push the start symbol on stack (node pointer points on tos): */
- Stack[ParserStackPointer] = ExprMalloc();
- Stack[ParserStackPointer] -> NodeKind = TOKENSTART;
- Stack[ParserStackPointer] -> Right =
- Stack[ParserStackPointer] -> Left = NULL;
-
- Token = GetToken(&Data); /* Get one look ahead token to start with. */
-
- while (TRUE) {
- if (IPGlblParseError)
- return NULL;
-
- Temp1 = ParserStackPointer; /* Find top active token (<1000). */
- while (Stack[Temp1] -> NodeKind >= 1000)
- Temp1--;
- /* Now test to see if the new token completes an handle: */
- if (TestPreceeding(Stack[Temp1] -> NodeKind, Token)) {
- switch (Token) {
- case CLOSPARA:
- if (Stack[Temp1] -> NodeKind == OPENPARA) {
- ExprFree(Stack[Temp1]); /* Free open paran. */
- Stack[Temp1] = NULL;
- /* If a parameter is introduced instead of function */
- /* it will be reduced already against "(" and it */
- /* probably was missspelled function... */
- if (Stack[Temp1 - 1] -> NodeKind == PARAMETER + 1000) {
- strcpy(IPGlblCharData,
- Stack[Temp1 - 1] -> PObj -> Name);
- IPGlblParseError = IP_ERR_UNDEF_FUNC;
- return NULL;
- }
-
- if (IS_USER_FUNCTION(Stack[Temp1 - 1] -> NodeKind)) {
- if (ParserStackPointer - Temp1 == 1) {
- Stack[ParserStackPointer] -> NodeKind -= 1000;
- Stack[Temp1 - 1] -> NodeKind += 1000;
- Stack[Temp1 - 1] -> Right =
- Stack[ParserStackPointer];
- ParserStackPointer -= 2;
- }
- else {
- Stack[Temp1 - 1] -> NodeKind += 1000;
- Stack[Temp1 - 1] -> Right = NULL;
- ParserStackPointer--;
- }
- }
- else if (IS_NO_PARAM_FUNC(Stack[Temp1 - 1] -> NodeKind)) {
- if (ParserStackPointer - Temp1 == 1) {
- UpdateCharError("",
- Stack[Temp1 - 1] -> NodeKind,
- Stack[Temp1 - 1]);
- IPGlblParseError = IP_ERR_NO_PARAM_FUNC;
- return NULL;
- }
- Stack[Temp1 - 1] -> NodeKind += 1000;
- Stack[Temp1 - 1] -> Right = NULL;
- ParserStackPointer--;
- }
- else if (IS_FUNCTION(Stack[Temp1 - 1] -> NodeKind)) {
- if (ParserStackPointer - Temp1 != 1) {
- UpdateCharError("",
- Stack[Temp1 - 1] -> NodeKind,
- Stack[Temp1 - 1]);
- IPGlblParseError = IP_ERR_PARAM_FUNC;
- return NULL;
- }
- Stack[ParserStackPointer] -> NodeKind -= 1000;
- Stack[Temp1 - 1] -> NodeKind += 1000;
- Stack[Temp1 - 1] -> Right =
- Stack[ParserStackPointer];
- ParserStackPointer -= 2;
- }
- else {
- if (ParserStackPointer - Temp1 != 1) {
- IPGlblParseError = IP_ERR_PARAM_MATCH;
- return NULL;
- }
- Stack[Temp1] = Stack[ParserStackPointer--];
- }
- Token = GetToken(&Data); /* Get another token. */
- continue;
- }
- else if (Stack[Temp1] -> NodeKind == TOKENSTART) {
- /* No match for this one! */
- IPGlblParseError = IP_ERR_PARAM_MATCH;
- return NULL;
- }
- break;
- case TOKENEND:
- if (Stack[Temp1] -> NodeKind == TOKENSTART) {
- if (ParserStackPointer != 1) {
- IPGlblParseError = IP_ERR_WRONG_SYNTAX;
- return NULL;
- }
- InptPrsrFreeTree(Stack[Temp1]); /* The TOKENSTART. */
- Stack[1] -> NodeKind -= 1000;
- return Stack[1];
- }
- }
-
- Temp2 = Temp1 - 1; /* Find the lower bound of handle. */
- while (Temp2 >= 0 && Stack[Temp2] -> NodeKind >= 1000)
- Temp2--;
- LowHandle = Temp2 + 1;
- if (LowHandle < 1) { /* No low bound was found. */
- IPGlblParseError = IP_ERR_WRONG_SYNTAX;
- return NULL; /* We ignore data till now. */
- }
- switch (ParserStackPointer - LowHandle + 1) {
- case 1: /* Its a scalar one - mark it as used (add 1000). */
- switch (Stack[ParserStackPointer] -> NodeKind) {
- case NUMBER:
- case PARAMETER:
- case STRING:
- Stack[ParserStackPointer] -> NodeKind += 1000;
- break;
- default:
- UpdateCharError("Found ",
- Stack[ParserStackPointer] -> NodeKind,
- Stack[ParserStackPointer]);
- IPGlblParseError = IP_ERR_PARAM_EXPECT;
- return NULL;
- }
- break;
- case 2: /* Its a monadic operator - create the subtree. */
- switch (Stack[ParserStackPointer - 1] -> NodeKind) {
- case BOOL_NOT:
- case UNARMINUS:
- Stack[ParserStackPointer - 1] -> Right =
- Stack[ParserStackPointer];
- Stack[ParserStackPointer] -> NodeKind -= 1000;
- Stack[ParserStackPointer - 1] -> NodeKind += 1000;
- ParserStackPointer--;
- break;
- case OPENPARA:
- IPGlblParseError = IP_ERR_PARAM_MATCH;
- return NULL;
- default:
- if (IS_AN_OPERATOR(Stack[ParserStackPointer] ->
- NodeKind))
- UpdateCharError("Found ",
- Stack[ParserStackPointer] -> NodeKind,
- Stack[ParserStackPointer]);
- else
- UpdateCharError("Found ",
- Stack[ParserStackPointer - 1] -> NodeKind,
- Stack[ParserStackPointer - 1]);
-
- IPGlblParseError = IP_ERR_ONE_OPERAND;
- return NULL;
- }
- break;
- case 3: /* Its a diadic operator - create the subtree. */
- switch (Stack[ParserStackPointer - 1] -> NodeKind) {
- case PLUS:
- case MINUS:
- case MULT:
- case DIV:
- case POWER:
- case COMMA:
- case EQUAL:
- case CMP_EQUAL:
- case CMP_NOTEQUAL:
- case CMP_LSEQUAL:
- case CMP_GTEQUAL:
- case CMP_LESS:
- case CMP_GREAT:
- case BOOL_AND:
- case BOOL_OR:
- case COLON:
- Stack[ParserStackPointer - 1] -> Right =
- Stack[ParserStackPointer];
- Stack[ParserStackPointer - 1] -> Left =
- Stack[ParserStackPointer - 2];
- Stack[ParserStackPointer - 2] -> NodeKind -= 1000;
- Stack[ParserStackPointer] -> NodeKind -= 1000;
- Stack[ParserStackPointer - 1] -> NodeKind += 1000;
- Stack[ParserStackPointer - 2] =
- Stack[ParserStackPointer - 1];
- ParserStackPointer -= 2;
- break;
- default:
- UpdateCharError("Found Operator ",
- Stack[ParserStackPointer - 1] -> NodeKind,
- Stack[ParserStackPointer - 1]);
- IPGlblParseError = IP_ERR_TWO_OPERAND;
- return NULL;
- }
- break;
- default:
- IPGlblParseError = IP_ERR_WRONG_SYNTAX;
- return NULL;
- }
- }
- else { /* Push that token on stack - it is not handle yet. */
- Stack[++ParserStackPointer] = ExprMalloc();
-
- # ifdef DEBUG1
- if (MaxStackPointer < ParserStackPointer)
- MaxStackPointer = ParserStackPointer;
- # endif /* DEBUG1 */
-
- if (ParserStackPointer == MAX_PARSER_STACK - 1) {
- IPGlblParseError = IP_ERR_STACK_OV;
- return NULL; /* We ignore data till now. */
- }
- if ((Stack[ParserStackPointer] -> NodeKind = Token) == USERINSTDEF)
- Stack[ParserStackPointer] -> UserFunc = IPGlblUserFunc;
- Stack[ParserStackPointer] -> PObj = NULL;
- Stack[ParserStackPointer] -> Right =
- Stack[ParserStackPointer] -> Left = NULL;
- if (Token == NUMBER) {
- Stack[ParserStackPointer] -> PObj = GenNUMValObject(Data);
- }
- else if (Token == PARAMETER) {
- if ((Stack[ParserStackPointer] -> PObj =
- GetObject(IPGlblCharData)) == NULL) {
- /* Its new one - allocate memory for it. Create a */
- /* numeric object as a reasonable default. */
- Stack[ParserStackPointer] -> PObj =
- IPAllocObject(IPGlblCharData, IP_OBJ_UNDEF, NULL);
- InsertObject(Stack[ParserStackPointer] -> PObj);
- }
- Stack[ParserStackPointer] -> PObj -> Count++;
- }
- else if (Token == STRING) {
- Stack[ParserStackPointer] -> PObj =
- IPAllocObject("", IP_OBJ_STRING, NULL);
- strcpy(Stack[ParserStackPointer] -> PObj -> U.Str,
- IPGlblCharData);
- Stack[ParserStackPointer] -> PObj -> Count++;
- }
- Token = GetToken(&Data); /* And get new token from stream. */
- }
- }
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to test precedence of two tokens. returns 0, <0 or >0 according to *
- * comparison results. *
- * *
- * PARAMETERS: *
- * Token1, Token2: Tokens to compare. *
- * *
- * RETURN VALUE: *
- * int: <0, 0, >0 comparison's result. *
- *****************************************************************************/
- static int TestPreceeding(int Token1, int Token2)
- {
- int Preced1 = 0,
- Preced2 = 0;
-
- if ((Token1 >= 1000) || (Token2 >= 1000))
- return FALSE; /* Ignore sub-expr. */
-
- if (IS_FUNCTION(Token1))
- Preced1 = 160;
- else {
- switch (Token1) {
- case TOKENSTART:
- case TOKENEND:
- Preced1 = 10;
- break;
- case OPENPARA:
- Preced1 = 20;
- break;
- case COMMA:
- Preced1 = 30;
- break;
- case COLON:
- Preced1 = 40;
- break;
- case BOOL_AND:
- case BOOL_OR:
- Preced1 = 50;
- break;
- case EQUAL:
- case CMP_EQUAL:
- case CMP_NOTEQUAL:
- case CMP_LSEQUAL:
- case CMP_GTEQUAL:
- case CMP_LESS:
- case CMP_GREAT:
- Preced1 = 55;
- break;
- case PLUS:
- case MINUS:
- Preced1 = 80;
- break;
- case MULT:
- case DIV:
- Preced1 = 100;
- break;
- case POWER:
- Preced1 = 120;
- break;
- case UNARMINUS:
- case BOOL_NOT:
- Preced1 = 125;
- break;
- case NUMBER:
- case PARAMETER:
- case STRING:
- case CLOSPARA:
- Preced1 = 180;
- break;
-
- }
- }
-
- if (IS_FUNCTION(Token2))
- Preced2 = 150;
- else {
- switch (Token2) {
- case TOKENSTART:
- case TOKENEND:
- Preced2 = 0;
- break;
- case CLOSPARA:
- Preced2 = 15;
- break;
- case COMMA:
- Preced2 = 30;
- break;
- case COLON:
- Preced2 = 40;
- break;
- case BOOL_AND:
- case BOOL_OR:
- Preced2 = 50;
- break;
- case EQUAL:
- case CMP_EQUAL:
- case CMP_NOTEQUAL:
- case CMP_LSEQUAL:
- case CMP_GTEQUAL:
- case CMP_LESS:
- case CMP_GREAT:
- Preced2 = 55;
- break;
- case PLUS:
- case MINUS:
- Preced2 = 70;
- break;
- case MULT:
- case DIV:
- Preced2 = 90;
- break;
- case POWER:
- Preced2 = 110;
- break;
- case UNARMINUS:
- case BOOL_NOT:
- Preced2 = 130;
- break;
- case NUMBER:
- case PARAMETER:
- case STRING:
- case OPENPARA:
- Preced2 = 170;
- break;
-
- }
- }
-
- return Preced1 - Preced2 > 0;
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to provide a description, gievn Token and optionally a Node. *
- * *
- * PARAMETERS: *
- * Token: With the fault. *
- * Node: Optional node at fault. *
- * *
- * RETURN VALUE: *
- * char *: Description of error. *
- *****************************************************************************/
- static char *UpdateCharErrorAux(int Token, ParseTree *Node)
- {
- static char TmpStr[LINE_LEN];
- char *TokenChar = NULL;
-
- if (Token > 1000)
- Token -= 1000;
-
- if (IS_NUM_FUNCTION(Token))
- TokenChar = NumFuncTable[Token - NUM_FUNC_OFFSET].FuncName;
- else if (IS_OBJ_FUNCTION(Token))
- TokenChar = ObjFuncTable[Token - OBJ_FUNC_OFFSET].FuncName;
- else if (IS_GEN_FUNCTION(Token))
- TokenChar = GenFuncTable[Token - GEN_FUNC_OFFSET].FuncName;
- else {
- switch (Token) {
- case PLUS:
- TokenChar = "+";
- break;
- case MINUS:
- TokenChar = "-";
- break;
- case MULT:
- TokenChar = "*";
- break;
- case DIV:
- TokenChar = "/";
- break;
- case POWER:
- TokenChar = "^";
- break;
- case UNARMINUS:
- TokenChar = "(Unary) -";
- break;
- case EQUAL:
- TokenChar = "=";
- break;
- case COMMA:
- TokenChar = ",";
- break;
- case COLON:
- TokenChar = ":";
- break;
- case SEMICOLON:
- TokenChar = ";";
- break;
- case CMP_EQUAL:
- TokenChar = "==";
- break;
- case CMP_NOTEQUAL:
- TokenChar = "!=";
- break;
- case CMP_LSEQUAL:
- TokenChar = "<=";
- break;
- case CMP_GTEQUAL:
- TokenChar = ">=";
- break;
- case CMP_LESS:
- TokenChar = "<";
- break;
- case CMP_GREAT:
- TokenChar = ">";
- break;
- case BOOL_AND:
- TokenChar = "&&";
- break;
- case BOOL_OR:
- TokenChar = "||";
- break;
- case BOOL_NOT:
- TokenChar = "!";
- break;
- case OPENPARA:
- TokenChar = "(";
- break;
- case CLOSPARA:
- TokenChar = ")";
- break;
- case NUMBER:
- if (Node && Node -> PObj && IP_IS_NUM_OBJ(Node -> PObj)) {
- sprintf(TmpStr, "%g", Node -> PObj -> U.R);
- TokenChar = TmpStr;
- }
- else
- TokenChar = "Numeric";
- break;
- case PARAMETER:
- if (Node && Node -> PObj && strlen(Node -> PObj -> Name) > 0)
- TokenChar = Node -> PObj -> Name;
- else
- TokenChar = "Parameter";
- break;
- case STRING:
- if (Node && Node -> PObj && IP_IS_STR_OBJ(Node -> PObj)) {
- TokenChar = Node -> PObj -> U.Str;
- }
- else
- TokenChar = "String";
- break;
- case USERINSTDEF:
- case USERFUNCDEF:
- case USERPROCDEF:
- TokenChar = "UserFunc";
- break;
- default:
- sprintf(TmpStr, "Token %d\n", Token);
- TokenChar = TmpStr;
- break;
- }
- }
-
- return TokenChar;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to update the character error message according to StrMsg & Token M
- * Node is optional and if not NULL, will be used to get better details. M
- * *
- * PARAMETERS: M
- * StrMsg: Some description of error. M
- * Token: Token at fault. M
- * Node: Optional Node at fault. M
- * *
- * RETURN VALUE: M
- * void M
- * *
- * KEYWORDS: M
- * UpdateCharError M
- *****************************************************************************/
- void UpdateCharError(char *StrMsg, int Token, ParseTree *Node)
- {
- char
- *TokenChar = UpdateCharErrorAux(Token, Node);
-
- sprintf(IPGlblCharData, "%s\"%s\"", StrMsg, TokenChar);
- if (IS_AN_OPERATOR(Token) && Node) {
- if (Node -> Left) {
- char *StrType =
- InptPrsrTypeToStr(InptPrsrTypeCheck(Node -> Left, 1));
-
- sprintf(&IPGlblCharData[strlen(IPGlblCharData)],
- "\n\tLeft Operand: \"%s\" (%s type)",
- UpdateCharErrorAux(Node -> Left -> NodeKind,
- Node -> Left),
- StrType);
- }
- if (Node -> Right) {
- char *StrType =
- InptPrsrTypeToStr(InptPrsrTypeCheck(Node -> Right, 1));
-
- sprintf(&IPGlblCharData[strlen(IPGlblCharData)],
- "\n\tRight Operand: \"%s\" (%s type)",
- UpdateCharErrorAux(Node -> Right -> NodeKind,
- Node -> Right),
- StrType);
- }
- }
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to get the next token out of the expression. *
- * Returns next token found and sets Data to the returned value (if any). *
- * *
- * PARAMETERS: *
- * Data: Real numbers will be saved herein. *
- * *
- * RETURN VALUE: *
- * int: Numeric value of next token. *
- *****************************************************************************/
- static int GetToken(RealType *Data)
- {
- int i,
- RetVal = TOKEN_NONE;
- char c;
-
- while (isspace(c = InptPrsrGetC(FALSE))); /* Skip white blanks. */
-
- if (c == '"') { /* Its a string token - read up to next ". */
- i = 0;
- while ((IPGlblCharData[i] = InptPrsrGetC(TRUE)) != '"') {
- if (IPGlblCharData[i] == '\\') /* Its escape char. for next one: */
- IPGlblCharData[i] = InptPrsrGetC(TRUE);
- if (IPGlblCharData[i] < ' ' || i > LINE_LEN - 2) {
- RetVal = TOKENERROR;
- IPGlblCharData[i] = 0;
- IPGlblParseError = IP_ERR_STR_TOO_LONG;
- break;
- }
- i++;
- }
- if (RetVal != TOKENERROR) {
- IPGlblCharData[i] = 0;
- RetVal = STRING;
- }
- }
- else if (isalpha(c)) { /* Is it a variable/function name? */
- if (islower(c))
- IPGlblCharData[i = 0] = toupper(c);
- else
- IPGlblCharData[i = 0] = c;
-
- while (isalpha(c = InptPrsrGetC(FALSE)) || isdigit(c) || c == '_')
- if (islower(c))
- IPGlblCharData[++i] = toupper(c);
- else
- IPGlblCharData[++i] = c;
- IPGlblCharData[++i] = 0;
- InptPrsrUnGetC(c);
-
- if ((int) strlen(IPGlblCharData) >= OBJ_NAME_LEN) {
- RetVal = TOKENERROR;
- IPGlblParseError = IP_ERR_NAME_TOO_LONG;
- }
- else {
- RetVal = GetVarFuncToken(IPGlblCharData, Data);
- }
- }
- else if (isdigit(c) || (c == '.')) { /* Is it numeric data? */
- IPGlblCharData[i=0] = c;
-
- while (isdigit(c = InptPrsrGetC(FALSE)) || (c == '.') ||
- (c == 'e') || (c == 'E') || (c == 'e'))
- IPGlblCharData[++i] = c;
- /* Handle the special case of negative exponent ("111.111E-22"). */
- if (c == '-' && (IPGlblCharData[i] == 'e' ||
- IPGlblCharData[i] == 'E')) {
- IPGlblCharData[++i] = c;
- while (isdigit(c = InptPrsrGetC(FALSE)) || (c == '.'))
- IPGlblCharData[++i] = c;
- }
- IPGlblCharData[++i] = 0;
-
- InptPrsrUnGetC(c);
-
- # ifdef DOUBLE
- sscanf(IPGlblCharData, "%lf", Data);
- # else
- sscanf(IPGlblCharData, "%f", Data);
- # endif /* DOUBLE */
-
- RetVal = NUMBER;
- }
- else
- switch (c) {
- case '+':
- RetVal = PLUS;
- break;
- case '-':
- switch (IPGlblILastToken) {
- case 0: /* If first token (no last token yet). */
- case PLUS:
- case MINUS:
- case MULT:
- case DIV:
- case POWER:
- case COMMA:
- case EQUAL:
- case CMP_EQUAL:
- case CMP_NOTEQUAL:
- case CMP_LSEQUAL:
- case CMP_GTEQUAL:
- case CMP_LESS:
- case CMP_GREAT:
- case BOOL_AND:
- case BOOL_OR:
- case BOOL_NOT:
- case COLON:
- case UNARMINUS:
- case OPENPARA:
- RetVal = UNARMINUS;
- break;
- default:
- RetVal = MINUS;
- break;
- }
- break;
- case '*':
- RetVal = MULT; break;
- case '/':
- RetVal = DIV;
- break;
- case '^':
- RetVal = POWER;
- break;
- case '(':
- RetVal = OPENPARA;
- break;
- case ')':
- RetVal = CLOSPARA;
- break;
- case '=':
- switch (c = InptPrsrGetC(FALSE)) {
- case '=':
- RetVal = CMP_EQUAL;
- break;
- default:
- InptPrsrUnGetC(c);
- RetVal = EQUAL;
- break;
- }
- break;
- case '<':
- switch (c = InptPrsrGetC(FALSE)) {
- case '=':
- RetVal = CMP_LSEQUAL;
- break;
- default:
- InptPrsrUnGetC(c);
- RetVal = CMP_LESS;
- break;
- }
- break;
- case '>':
- switch (c = InptPrsrGetC(FALSE)) {
- case '=':
- RetVal = CMP_GTEQUAL;
- break;
- default:
- InptPrsrUnGetC(c);
- RetVal = CMP_GREAT;
- break;
- }
- break;
- case '&':
- if ((c = InptPrsrGetC(FALSE)) == '&') {
- RetVal = BOOL_AND;
- break;
- }
- else {
- RetVal = TOKENERROR;
- IPGlblCharData[0] = '&';
- IPGlblCharData[1] = c;
- IPGlblCharData[2] = 0;
- IPGlblParseError = IP_ERR_UNDEF_TOKEN;
- break;
- }
- case '|':
- if ((c = InptPrsrGetC(FALSE)) == '|') {
- RetVal = BOOL_OR;
- break;
- }
- else {
- RetVal = TOKENERROR;
- IPGlblCharData[0] = '|';
- IPGlblCharData[1] = c;
- IPGlblCharData[2] = 0;
- IPGlblParseError = IP_ERR_UNDEF_TOKEN;
- break;
- }
- case ',':
- RetVal = COMMA;
- break;
- case ':':
- RetVal = COLON;
- break;
- case ';':
- RetVal = TOKENEND;
- break; /* End of expression! */
- case '!':
- if ((c = InptPrsrGetC(FALSE)) == '=') {
- RetVal = CMP_NOTEQUAL;
- }
- else {
- InptPrsrUnGetC(c);
- RetVal = BOOL_NOT;
- }
- break;
- default:
- RetVal = TOKENERROR;
- IPGlblCharData[0] = c;
- IPGlblCharData[1] = 0;
- IPGlblParseError = IP_ERR_UNDEF_TOKEN;
- break;
- }
-
- IPGlblILastToken = RetVal;
-
- return RetVal;
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to test alpha Token for match with one of the defined functions *
- * and returns that Token function if found one. *
- * Otherwise it is assumed to be a user defined function or a variable. *
- * *
- * PARAMETERS: *
- * Token: Token to search, in string function. *
- * Data: Real numbers will be saved herein. *
- * *
- * RETURN VALUE: *
- * int: Token number *
- *****************************************************************************/
- static int GetVarFuncToken(char *Token, RealType *Data)
- {
- int i;
- char c;
- UserDefinedFuncDefType *UserFunc;
-
- if (strcmp("COMMENT", Token) == 0) {
- /* Get first nonspace char after the COMMENT key word: */
- while (isspace(c = InptPrsrGetC(FALSE)));
- /* And read the input until this char appear again (end of comment): */
- while (c != InptPrsrGetC(FALSE));
-
- return GetToken(Data); /* Return next token instead. */
- }
-
- for (UserFunc = UserDefinedFuncList;
- UserFunc != NULL;
- UserFunc = UserFunc -> Pnext)
- if (strcmp(UserFunc -> FuncName, Token) == 0) {
- while (isspace(c = InptPrsrGetC(FALSE))); /* Skip white blanks. */
- InptPrsrUnGetC(c);
- if (c == '(') {
- IPGlblUserFunc = UserFunc;
- return USERINSTDEF;
- }
- else
- break;
- }
- for (i = 0; i < NumFuncTableSize; i++) /* Is it Numeric function? */
- if (strcmp(NumFuncTable[i].FuncName, Token) == 0)
- return NumFuncTable[i].FuncToken;
- for (i = 0; i < ObjFuncTableSize; i++) /* Is it Object function? */
- if (strcmp(ObjFuncTable[i].FuncName, Token) == 0)
- return ObjFuncTable[i].FuncToken;
- for (i = 0; i < GenFuncTableSize; i++) /* Is it General function? */
- if (strcmp(GenFuncTable[i].FuncName, Token) == 0)
- return GenFuncTable[i].FuncToken;
-
- if (strcmp("FUNCTION", Token) == 0)
- return USERFUNCDEF;
- if (strcmp("PROCEDURE", Token) == 0)
- return USERPROCDEF;
-
- for (i = 0; i < ConstantTableSize; i++)/* Replace constant by its value. */
- if (strcmp(ConstantTable[i].FuncName, Token) == 0) {
- sprintf(Token, "%g", ConstantTable[i].Value);
- *Data = ConstantTable[i].Value;
- return NUMBER;
- }
-
- return PARAMETER; /* If not a function - it is assumed to be variable. */
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Sets echo level of source irt files. M
- * *
- * PARAMETERS: M
- * EchoSource: TRUE for echo, FALSE for no echo. M
- * *
- * RETURN VALUE: M
- * void M
- * *
- * KEYWORDS: M
- * InptPrsrEchoSource M
- *****************************************************************************/
- void InptPrsrEchoSource(int EchoSource)
- {
- GlblEchoSource = EchoSource;
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to control all getchar in this module and echo it if requested *
- * Note it handles the FileStack and decrease it if end of file was found. *
- * *
- * PARAMETERS: *
- * None *
- * *
- * RETURN VALUE: *
- * char: Next character in input stream. *
- *****************************************************************************/
- static char InptPrsrGetC(int InString)
- {
- static char *p,
- Line[INPUT_LINE_LEN] = "",
- TLine[INPUT_LINE_LEN] = "";
- static int
- LineLength = 0,
- LineCount = 0;
- char c;
- int i;
-
- if (UnGetChar == 0) { /* One level of unget char... */
- if (LineCount < LineLength) { /* Is there anything in local Line? */
- }
- else
- do {
- if (FileStackPtr == 0) {
- WndwInputWindowGetStr(Line, INPUT_LINE_LEN);
- LineCount = 0;
- }
- else {
- sprintf(Line, "%s > ", FileStack[FileStackPtr - 1].Name);
- LineCount = strlen(Line);
- if (fgets(TLine, INPUT_LINE_LEN,
- FileStack[FileStackPtr - 1].f) == NULL) {
- /* Its end of file - close it and update stack. */
- TLine[0] = 0;
- fclose(FileStack[--FileStackPtr].f);
- }
-
- /* Strip off CR/LF/TAB. */
- for (i = LineCount, p = TLine; *p != 0; p++) {
- if (*p == 0x09)
- do {
- Line[i++] = ' ';
- }
- while ((i - LineCount) % 8 != 0);
- else if (*p < ' ' || *p > '~')
- break;
- else
- Line[i++] = *p;
- }
- Line[i] = 0;
- }
-
- if (GlblEchoSource)
- #ifdef DJGCC
- WndwInputWindowPutStr(Line);
- #else
- if (FileStackPtr != 0) /* Input was from keyboard? */
- WndwInputWindowPutStr(Line);
- #endif /* DJGCC */
-
- LineLength = strlen(Line);
- } while (LineCount >= LineLength);
-
- c = Line[LineCount++];
- if (c == '#' && !InString) { /* Its a comment - skip that line. */
- c = ' '; /* Must return something. */
- LineCount = LineLength; /* Force next time to fetch new line. */
- }
- # ifdef DEBUG1
- fprintf(stderr, "%c", c);
- # endif /* DEBUG1 */
- }
- else {
- c = UnGetChar;
- UnGetChar = 0;
- }
-
- return c;
- }
-
- /*****************************************************************************
- * DESCRIPTION: *
- * Routine to unget one char *
- * *
- * PARAMETERS: *
- * c: Character to unget. *
- * *
- * RETURN VALUE: *
- * void *
- *****************************************************************************/
- static void InptPrsrUnGetC(char c)
- {
- UnGetChar = c;
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to quit reading until next ';'. If reading from files, they are M
- * all closed as well. M
- * *
- * PARAMETERS: M
- * FlushStdin: If not reading from a file, should we skip to next ';'? M
- * *
- * RETURN VALUE: M
- * void M
- * *
- * KEYWORDS: M
- * FlushToEndOfExpr M
- *****************************************************************************/
- void FlushToEndOfExpr(int FlushStdin)
- {
- if (FileStackPtr > 0) /* Close all the open files - back to stdin. */
- while (FileStackPtr)
- fclose(FileStack[--FileStackPtr].f);
- else if (FlushStdin && IPGlblILastToken != TOKENEND)
- while (InptPrsrGetC(FALSE) != ';');
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to push new file to read on the FileStack from INCLUDE command: M
- * *
- * PARAMETERS: M
- * PrmFileName: Name of file to start to read from. M
- * *
- * RETURN VALUE: M
- * void M
- * *
- * KEYWORDS: M
- * FileInclude M
- *****************************************************************************/
- void FileInclude(char *PrmFileName)
- {
- int i;
- FILE *f;
- char s[LINE_LEN], FileName[LINE_LEN], c, *p;
-
- if (FileStackPtr < FILE_STACK_SIZE) {
- strcpy(FileName, PrmFileName);
-
- if ((p = strstr(FileName, ".irt")) == NULL)
- strcat(FileName, ".irt");
-
- if ((f = fopen(FileName, "r")) != NULL) {
- FileStack[FileStackPtr].f = f;
- for (i = strlen(FileName) - 1; /* Isolate the file name. */
- i > 0 && (c = FileName[i]) != '\\' && c != '/' && c != ':';
- i--);
- if (i > 0)
- i++;
- strncpy(FileStack[FileStackPtr].Name, &FileName[i],
- FILE_NAME_LEN - 1);
- FileStackPtr++; /* Now next char is from that file! */
- }
- else {
- sprintf(s, "Cannt open file %s - ignored", FileName);
- WndwInputWindowPutStr(s);
- }
- }
- else
- WndwInputWindowPutStr("File nesting too deep - ignored");
- }
-
- /*****************************************************************************
- * DESCRIPTION: M
- * Routine to return parsing error if happen one, zero return value otherwise.M
- * *
- * PARAMETERS: M
- * Message: M
- * *
- * RETURN VALUE: M
- * InptPrsrEvalErrType: M
- * *
- * KEYWORDS: M
- * InptPrsrParseError M
- *****************************************************************************/
- InptPrsrEvalErrType InptPrsrParseError(char **Message)
- {
- InptPrsrEvalErrType Temp;
-
- *Message = IPGlblCharData;
- Temp = IPGlblParseError;
- IPGlblParseError = IPE_NO_ERR;
- return Temp;
- }
-